/*
 * FileManage.cpp
 *
 *  Created on: Mar 27, 2013
 *      Author: root
 */

#include "SvrFileManage.h"
#include <dirent.h>

SvrFileManage::SvrFileManage() {

	m_virtual_num = 0;
	this->pSvrconfig = NULL;
	this->pSvrlog = NULL;
}

SvrFileManage::~SvrFileManage() {
	 /*add your code here*/
}

/**
 * init svr file manage class
 */
int SvrFileManage::init(SvrConfig * pconfig, Svr_log * psvrlog)
{
	if(pconfig == NULL || psvrlog == NULL)
		return FAILURE;

	this->pSvrconfig = pconfig;
	this->pSvrlog = psvrlog;

	/*init virtual path map*/
	if(this->pSvrconfig->virtualpath != NULL)
	{
		this->set_vir_dir(this->pSvrconfig->virtualpath);
	}

	/*init del list*/
	this->del_content_list.init_list(true);


	return SUCCESS;
}

/*
*set virtual directory list
*/
bool SvrFileManage::set_vir_dir(const char * virliststr)
{
    if(virliststr == NULL)
         return false;

    char sz_virtual[FILE_MAX_PATH];
    if(strlen(virliststr) > FILE_MAX_PATH)
         return false;


    strcpy(sz_virtual,virliststr);

    char * pvirtual = sz_virtual;
    char * ch_begin = NULL;
    char * ch_end = NULL;
    int nch_len = 0 ;
    while(m_virtual_num < (int) VIR_DIR_MAP_NUM)
    {
        Virtual_Map vDirMap;
        ch_begin = strstr(pvirtual,"=");
        if(ch_begin != NULL)
        {
            nch_len = int(ch_begin - pvirtual);
            memset(vDirMap.vir_dir,'\0',FILE_MAX_PATH);
            memset(vDirMap.disc_dir,'\0',FILE_MAX_PATH);
            memcpy(vDirMap.vir_dir,pvirtual,nch_len);
            ch_end = strstr(ch_begin,"|");
            if(ch_end != NULL)
            {
                    nch_len = int(ch_end - ch_begin - 1);
                    memcpy(vDirMap.disc_dir ,ch_begin + 1,nch_len);
                    pvirtual = ch_end + 1;
            }
            else
            {
                    nch_len = int(strlen(ch_begin + 1));
                    memcpy(vDirMap.disc_dir,ch_begin + 1,nch_len);
                    m_virdirmap[m_virtual_num++] = vDirMap;
                    break;
            }
            m_virdirmap[m_virtual_num++] = vDirMap;
        }
        else
        {
            break;
        }
    }

    return true;
}

/*
*get virtual directory
*/
bool SvrFileManage::get_vir_dir(char * virname,char * buf, size_t buf_len)
{
    if(virname == NULL || buf == NULL || buf_len == 0)
            return false;

    /*find virtual name*/
    char * ch_find = NULL;
    int nch_len = 0;
    for(int i = 0;i< m_virtual_num;i++)
    {
        ch_find = strstr(virname,m_virdirmap[i].vir_dir);
        if(ch_find != NULL)
        {
              nch_len = int(ch_find - virname);
              strcpy(buf,m_virdirmap[i].disc_dir);
              strcat(buf,ch_find + strlen(m_virdirmap[i].vir_dir));
              break;
        }
    }
    if(strlen(buf) != 0)
    {
        return true;
    }
    else
    {
        /*if not find,copy default rootpath,and return false*/
        strcpy(buf,this->pSvrconfig->rootpath);
        return false;
    }
}


/*
* delete file
*/
bool SvrFileManage::delete_file(const char * filename)
{
      if(strlen(this->pSvrconfig->rootpath) == 0 || filename == NULL || strlen(filename) < 1)
      {
          return false;
      }

      int retvalue  = false;
      /*get vir name */
      char vir_name[FILE_MAX_PATH];
      char full_path[FILE_MAX_PATH];
      memset(vir_name,'\0',sizeof(vir_name));
      memset(full_path,'\0',sizeof(full_path));

      const char * fptr = strstr(filename + 1,"/");
      if(fptr != NULL)
      {
          size_t len = fptr - filename - 1;
          if(len > 0)
          {
              memcpy(vir_name,filename + 1,len);
          }
      }
      /*get vir dir */
      bool ret = this->get_vir_dir(vir_name,full_path,FILE_MAX_PATH);

      /*get file name*/
      if(ret)
      {
          strcat(full_path,fptr);
      }
      else
      {
          strcat(full_path,filename);
      }

      /*replace '\\' to '/' */
      size_t index = 0;
      size_t len = strlen(full_path);
      while(index < len)
      {
          if((*(full_path+index)) == '\\')
        	  (*(full_path+index)) = '/';
          /*next char*/
          index++;
      }

      /*delete file*/
      if(remove(full_path) == 0)
      {
          retvalue = true;
      }
      else
      {
          if(access(full_path,F_OK) != 0)
          {
              retvalue = true;
          }
          else
          {
              pSvrlog->log_fmt(LOG_ERR,"Delete File Error,Code:ERROR_ACCESS_DENIED,FileName:%s",filename);
          }
      }

      /*return result*/
      return retvalue;
}


/*
*add del content
*/
int SvrFileManage::add_deletefile(const char * fileName,int count)
{
	FileInfoData * pcontent = new FileInfoData();
	if(pcontent == NULL)
		return FAILURE;

	pcontent->count = count;
	pcontent->del_flag = 0;
	strcpy(pcontent->file_name,fileName);

	/*add to list*/
	this->del_content_list_lock.Lock();
	{
		this->del_content_list.push(pcontent);

		this->del_content_list_lock.Unlock();
	}

	return SUCCESS;
}

/*
*clear delete file
*/
int SvrFileManage::delete_file_list(void)
{
	BOOL ret = TRUE;
	this->del_content_list_lock.Lock();
	{
		bool delflag = false;
		FileInfoData * pcontent = this->del_content_list.get_first();
		int list_count = this->del_content_list.size();

		while(pcontent != NULL && list_count > 0)
		{
			if(pcontent->del_flag > 0 || (time(NULL) - pcontent->begin_time) > pcontent->count / 10)
			{
				/*delete file*/
				if(this->delete_file(pcontent->file_name))
				{
					delflag = true;
					break;
				}
				else
				{
					ret = FALSE;
					pcontent->del_flag ++;
					/*if del flag > 10 ,this file can not delete,close task*/
					if(pcontent->del_flag > 10)
					{
						pSvrlog->log_fmt(LOG_ERR,"Delete File retry 10 times failure,FileName:%s",pcontent->file_name);
						delflag = true;
						break;
					}
				}
			}

			/*next node*/
			list_count --;
			pcontent = pcontent->next;
		}

		/*free buf*/
		if(delflag && pcontent != NULL)
		{
			this->del_content_list.remove(pcontent);
			delete pcontent;
		}

		/*end*/
		this->del_content_list_lock.Unlock();
	}

	return ret;
}


/**
 * open file by filename
 * filesize:set file size
 * return : filefd, error -1
 */
int SvrFileManage::open_file(const char * filename,uint64_t & filesize,bool is_create_append)
{
	int fd = INVALID_HANDLE_VALUE;

	if(filename == NULL)
		return fd;

	/**
	 * create dir by filename
	 */
	if(is_create_append && !this->create_dir(filename))
	{
		return fd;
	}

	/**
	 * open file by file name
	 */
	int oflag = O_RDWR;
	if(is_create_append)
	{
		oflag = O_RDWR | O_CREAT | O_APPEND;
	}
	fd = open(filename,oflag);
	/*
	 * get file size
	 */
	if(fd >= 0)
	{
		struct stat sb;
		if (fstat(fd, &sb) >= 0)
		{
			filesize = (unsigned long) sb.st_size;
			if(filesize > 0)
			{
				pSvrlog->log_fmt(LOG_INFO,"open file %s , size :%u\r\n",filename,filesize);
			}
		}
	}

	/*reset file offset*/
	if(fd >= 0 && !is_create_append)
	{
		lseek(fd, 0, SEEK_SET);
		fcntl(fd, F_SETFD, FD_CLOEXEC);
	}

	return fd;
}


/*
 * create dir by file full path
 * */
bool SvrFileManage::create_dir(const char * filename)
{
	if(filename == NULL)
		return false;

	/*check first char*/
	if(filename[0] != '/')
	{
		return false;
	}

	DIR * dp = NULL;
	mode_t dir_mt = S_IRUSR | S_IWUSR;
	char path[FILE_MAX_PATH];
	size_t len = strlen(filename);
	size_t index = 0;

	while(index < len)
	{
		if(filename[index] == '/' && index  > 1)
		{
			memset(path,'\0',FILE_MAX_PATH);
			memcpy(path,filename,index);
			dp = opendir (path);
			if (dp == NULL)
			{
				if(0 != mkdir(path,dir_mt))
				{
					return false;
				}
			}
			else
			{
				(void) closedir (dp);
				dp = NULL;
			}
		}

		/**
		 * next char
		 */
		index ++;
	}


	return true;
}

/**
 * run
 * tick:useconds
 */
void SvrFileManage::run(long tickvalue)
{
	if(this->FileClearTick * tickvalue > 30000000)
	{
		this->delete_file_list();
		this->FileClearTick = 0;
	}

	this->FileClearTick ++;
}
